/*
 *
 *  Copyright (C) 1994-2017, OFFIS e.V.
 *  All rights reserved.  See COPYRIGHT file for details.
 *
 *  This software and supporting documentation were developed by
 *
 *    OFFIS e.V.
 *    R&D Division Health
 *    Escherweg 2
 *    D-26121 Oldenburg, Germany
 *
 *
 *  Module:  dcmdata
 *
 *  Author:  Andrew Hewett
 *
 *  Purpose:
 *  Generate a builtin data dictionary which can be compiled into
 *  the dcmdata library.
 *
 */

#include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
#include "dcmtk/dcmdata/dcdict.h"
#include "dcmtk/dcmdata/cmdlnarg.h"
#include "dcmtk/ofstd/ofstring.h"
#include "dcmtk/ofstd/ofdatime.h"
#include "dcmtk/ofstd/ofstd.h"
#include "dcmtk/dcmdata/dcdicent.h"

#define PRIVATE_TAGS_IFNAME "ENABLE_PRIVATE_TAGS"

void
DcmDataDictionary::loadBuiltinDictionary()
{
  /*
   * * Empty Stub.
   **
   ** Used to keep compiler happy when building mkdictbi since it links itself
   ** against dcdict.cc.
   */
}

static const char*
rr2s(DcmDictRangeRestriction rr)
{
    const char* s;
    switch (rr) {
    case DcmDictRange_Unspecified:
        s = "DcmDictRange_Unspecified";
        break;
    case DcmDictRange_Odd:
        s = "DcmDictRange_Odd";
        break;
    case DcmDictRange_Even:
        s = "DcmDictRange_Even";
        break;
    default:
        s = "DcmDictRange_GENERATOR_ERROR";
        break;
    }
    return s;
}

static void
printSimpleEntry(FILE* fout, const DcmDictEntry* e, OFBool& isFirst, OFBool& isPrivate)
{

    const char *c = e->getPrivateCreator();

    if (c && !isPrivate)
    {
       fprintf(fout, "#ifdef %s\n", PRIVATE_TAGS_IFNAME);
       isPrivate = OFTrue;
    }
    else if (isPrivate && !c)
    {
       fprintf(fout, "#endif\n");
       isPrivate = OFFalse;
    }

    if (isFirst)
    {
      fprintf(fout, "    ");
      isFirst = OFFalse;
    } else fprintf(fout, "  , ");

    fprintf(fout, "{ 0x%04x, 0x%04x, 0x%04x, 0x%04x,\n",
            e->getGroup(), e->getElement(),
            e->getUpperGroup(), e->getUpperElement());
    fprintf(fout, "      EVR_%s, \"%s\", %d, %d, \"%s\",\n",
            e->getVR().getVRName(),
            e->getTagName(),
            e->getVMMin(), e->getVMMax(),
            OFSTRING_GUARD(e->getStandardVersion()));
    fprintf(fout, "      %s, %s,\n", rr2s(e->getGroupRangeRestriction()),
            rr2s(e->getElementRangeRestriction()));

    if (c)
      fprintf(fout, "      \"%s\" }\n", c);
    else
      fprintf(fout, "      NULL }\n");
}

//int
//main(int argc, char* argv[])
//{
//    char* progname;
//    const char* filename = NULL;
//    FILE* fout = NULL;
//    DcmDictEntry* e = NULL;

//    OFStandard::initializeNetwork();

//    prepareCmdLineArgs(argc, argv, "mkdictbi");

//    DcmDataDictionary& globalDataDict = dcmDataDict.wrlock();

//    /* clear out any preloaded dictionary */
//    globalDataDict.clear();

//    progname = argv[0];

//    if (argc >= 3 && 0 == strcmp(argv[1], "-o")) {
//        filename = argv[2];
//        argv += 2;
//        argc -= 2;
//    }

//    int i;
//    for (i=1; i<argc; i++) {
//        globalDataDict.loadDictionary(argv[i]);
//    }

//    if (filename) {
//        fout = fopen(filename, "w");
//        if (!fout) {
//            fprintf(stderr, "Failed to open file \"%s\", giving up\n", filename);
//            return -1;
//        }
//    } else {
//        fout = stdout;
//    }

//    OFString dateString;
//    OFDateTime::getCurrentDateTime().getISOFormattedDateTime(dateString);

//    /* generate c++ code for static dictionary */

//    fprintf(fout, "/*\n");
//    fprintf(fout, "** DO NOT EDIT THIS FILE !!!\n");
//    fprintf(fout, "** It was generated automatically by:\n");
//#ifndef SUPPRESS_CREATE_STAMP
//    fputs("**\n", fout);
//    fprintf(fout, "**   User: %s\n", OFStandard::getUserName().c_str());
//    fprintf(fout, "**   Host: %s\n", OFStandard::getHostName().c_str());
//    fprintf(fout, "**   Date: %s\n", dateString.c_str());
//#endif
//    fprintf(fout, "**   Prog: %s\n", progname);
//    fputs("**\n", fout);
//    if (argc > 1) {
//        fprintf(fout, "**   From: %s\n", argv[1]);
//        for (i=2; i<argc; i++) {
//            fprintf(fout, "**         %s\n", argv[i]);
//        }
//    }
//    fputs("**\n", fout);
//    fprintf(fout, "*/\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "#include \"dcmtk/dcmdata/dcdict.h\"\n");
//    fprintf(fout, "#ifdef ENABLE_BUILTIN_DICTIONARY\n");
//    fprintf(fout, "#include \"dcmtk/dcmdata/dcdicent.h\"\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "struct DBI_SimpleEntry {\n");
//    fprintf(fout, "    Uint16 group;\n");
//    fprintf(fout, "    Uint16 element;\n");
//    fprintf(fout, "    Uint16 upperGroup;\n");
//    fprintf(fout, "    Uint16 upperElement;\n");
//    fprintf(fout, "    DcmEVR evr;\n");
//    fprintf(fout, "    const char* tagName;\n");
//    fprintf(fout, "    int vmMin;\n");
//    fprintf(fout, "    int vmMax;\n");
//    fprintf(fout, "    const char* standardVersion;\n");
//    fprintf(fout, "    DcmDictRangeRestriction groupRestriction;\n");
//    fprintf(fout, "    DcmDictRangeRestriction elementRestriction;\n");
//    fprintf(fout, "    const char* privateCreator;\n");
//    fprintf(fout, "};\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "static const DBI_SimpleEntry simpleBuiltinDict[] = {\n");

//    OFBool isFirst = OFTrue;
//    OFBool isPrivate = OFFalse;

//    /*
//    ** the hash table does not maintain ordering so we must put
//    ** all the entries into a sorted list.
//    */
//    DcmDictEntryList list;
//    DcmHashDictIterator iter(globalDataDict.normalBegin());
//    DcmHashDictIterator last(globalDataDict.normalEnd());
//    for (; iter != last; ++iter) {
//        e = new DcmDictEntry(*(*iter));
//        list.insertAndReplace(e);
//    }
//    /* output the list contents */

//    /* non-repeating standard elements */
//    DcmDictEntryListIterator listIter(list.begin());
//    DcmDictEntryListIterator listLast(list.end());
//    for (; listIter != listLast; ++listIter)
//    {
//        printSimpleEntry(fout, *listIter, isFirst, isPrivate);
//    }

//    /* repeating standard elements */
//    DcmDictEntryListIterator repIter(globalDataDict.repeatingBegin());
//    DcmDictEntryListIterator repLast(globalDataDict.repeatingEnd());
//    for (; repIter != repLast; ++repIter)
//    {
//        printSimpleEntry(fout, *repIter, isFirst, isPrivate);
//    }

//    if (isPrivate)
//    {
//       fprintf(fout, "#endif\n");
//    }

//    fprintf(fout, "\n};\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "static const size_t simpleBuiltinDict_count =\n");
//    fprintf(fout, "    sizeof(simpleBuiltinDict)/sizeof(DBI_SimpleEntry);\n");
//    fprintf(fout, "\n");

//    fprintf(fout, "\n");
//    fprintf(fout, "void\n");
//    fprintf(fout, "DcmDataDictionary::loadBuiltinDictionary()\n");
//    fprintf(fout, "{\n");
//    fprintf(fout, "    DcmDictEntry* e = NULL;\n");
//    fprintf(fout, "    const DBI_SimpleEntry *b = simpleBuiltinDict;\n");
//    fprintf(fout, "    for (size_t i=0; i<simpleBuiltinDict_count; ++i) {\n");
//    fprintf(fout, "        b = simpleBuiltinDict + i;\n");
//    fprintf(fout, "        e = new DcmDictEntry(b->group, b->element,\n");
//    fprintf(fout, "            b->upperGroup, b->upperElement, b->evr,\n");
//    fprintf(fout, "            b->tagName, b->vmMin, b->vmMax,\n");
//    fprintf(fout, "            b->standardVersion, OFFalse, b->privateCreator);\n");
//    fprintf(fout, "        e->setGroupRangeRestriction(b->groupRestriction);\n");
//    fprintf(fout, "        e->setElementRangeRestriction(b->elementRestriction);\n");
//    fprintf(fout, "        addEntry(e);\n");
//    fprintf(fout, "    }\n");
//    fprintf(fout, "}\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "#else // WITH_BUILTIN_DICTIONARY\n");
//    fprintf(fout, "void\n");
//    fprintf(fout, "DcmDataDictionary::loadBuiltinDictionary()\n");
//    fprintf(fout, "{\n");
//    fprintf(fout, "/*\n");
//    fprintf(fout, " ** Empty Stub.\n");
//    fprintf(fout, " **\n");
//    fprintf(fout, " ** We don't want a populated built-in data dictionary. In order to enable it,\n");
//    fprintf(fout, " ** define WITH_BUILTIN_DICTIONARY. To re-create the builtin dictionary from\n");
//    fprintf(fout, " ** a textfile like dicom.dic, use dcmdata/libsrc/mkdictbi.\n");
//    fprintf(fout, "*/\n");
//    fprintf(fout, "}\n");
//    fprintf(fout, "\n");
//    fprintf(fout, "#endif // WITH_BUILTIN_DICTIONARY\n");
//    fprintf(fout, "\n");
//    dcmDataDict.unlock();
//    if (filename)
//    {
//        fclose(fout);
//    }
//    return 0;
//}
